using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Security.Permissions;
using needle.UI.Controls.Flat.Utilities;
using needle.UI.Controls.Flat.Utilities.Win32;
using needle.UI.Controls.Flat.Windows.Docking;
using needle.UI.Controls.Flat.Windows.Forms.Collections;

namespace needle.UI.Controls.Flat.Windows.Docking
{
	public class FloatingForm : Form, IHotZoneSource, IMessageFilter
	{
		private const int HitTestCaption = 2;

        protected Zone mzone;
        protected bool mintercept;
        protected RedockerContent mredocker;
        protected DockingManager mdockingManager;

        public event ContextEventHandler Context;
        
		#region Constructors

		public FloatingForm(DockingManager dockingManager, Zone zone, ContextEventHandler contextHandler)
        {
            this.StartPosition = FormStartPosition.Manual;

            this.ShowInTaskbar = false;
        
            this.Owner = dockingManager.Container.FindForm();
            
            this.ControlRemoved += new ControlEventHandler(OnZoneRemoved);
            
            Controls.Add(zone);

            mredocker = null;
            mintercept = false;
            mzone = zone;
            mdockingManager = dockingManager;

            if (contextHandler != null)
                this.Context += contextHandler;	

            this.BackColor = mdockingManager.BackColor;
            this.ForeColor = mdockingManager.InactiveTextColor;

            mzone.Windows.Inserted += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowInserted);
            mzone.Windows.Removing += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowRemoving);
            mzone.Windows.Removed += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowRemoved);

            if (mzone.Windows.Count == 1)
            {
                mzone.Windows[0].HideDetails(); 
                
                mzone.Windows[0].FullTitleChanged += new EventHandler(OnFullTitleChanged);  

                this.Text = mzone.Windows[0].FullTitle;
            }
            
            Application.AddMessageFilter(this);
        }

		#endregion

		#region Virtuals
           
        protected void OnWindowInserted(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
        {
            if (mzone.Windows.Count == 1)
            {
                mzone.Windows[0].HideDetails();                
                
                mzone.Windows[0].FullTitleChanged += new EventHandler(OnFullTitleChanged);  

                this.Text = mzone.Windows[0].FullTitle;
            }
            else if (mzone.Windows.Count == 2)
            {
				int pos = 0;
			
				if (e.Index == 0)
					pos++;

                mzone.Windows[pos].ShowDetails();                
                
                mzone.Windows[pos].FullTitleChanged -= new EventHandler(OnFullTitleChanged);  

                this.Text = "";
            }
        }
           
        protected void OnWindowRemoving(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
        {
            if (mzone.Windows.Count == 1)
            {   
                mzone.Windows[0].ShowDetails();                
                
                mzone.Windows[0].FullTitleChanged -= new EventHandler(OnFullTitleChanged);  
                
                this.Text = "";
            }
        }

        protected void OnWindowRemoved(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
        {
            if (mzone.Windows.Count == 1)
            {   
                mzone.Windows[0].HideDetails();                

                mzone.Windows[0].FullTitleChanged += new EventHandler(OnFullTitleChanged);  
                
                this.Text = mzone.Windows[0].FullTitle;
            }
        }
        
        protected void OnFullTitleChanged(object sender, EventArgs e)
        {
            this.Text = (string)sender;
        }
        
        protected void OnZoneRemoved(object sender, ControlEventArgs e)
        {
			if (e.Control == mzone)
			{
				if (mzone.Windows.Count == 1)
				{   
					mzone.Windows[0].ShowDetails();                

					mzone.Windows[0].FullTitleChanged -= new EventHandler(OnFullTitleChanged);  
				}
        
				mzone.Windows.Inserted -= new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowInserted);
				mzone.Windows.Removing -= new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowRemoving);
				mzone.Windows.Removed -= new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnWindowRemoved);

				this.Dispose();
			}
        }

		protected void Restore()
		{
			if (mzone != null)
			{
				ContentCollection cc = ZoneHelper.Contents(mzone);

				foreach(Content c in cc)
				{
					c.RecordFloatingRestore();
					c.Docked = true;
				}

				foreach(Content c in cc)
					mdockingManager.HideContent(c, false, true);
				
				foreach(Content c in cc)
					mdockingManager.ShowContent(c);

				mdockingManager.UpdateInsideFill();
			}

			this.Close();
		}

        public virtual void OnContext(Point screenPos)
        {
            if (Context != null)
                Context(this, new ContextEventArgs(screenPos));
        }

		[SecurityPermission(SecurityAction.LinkDemand)]
		[UseApiElements("WM_NCLBUTTONDBLCLK, WM_NCLBUTTONDOWN, POINT, WM_MOUSEMOVE, WM_MBUTTONDOWN, WM_RBUTTONDOWN")]
		protected override void WndProc(ref Message m)
		{
			if (m.Msg == (int)Msgs.WM_NCLBUTTONDBLCLK)
			{
				Restore();

				return;
			}
			else if (m.Msg == (int)Msgs.WM_NCLBUTTONDOWN)
			{
				if (!mintercept)
				{
					int result = (int)User32.SendMessage(this.Handle, (int)Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
                
					if (result == HitTestCaption)
					{
						mintercept = true;
                    
						this.Capture = true;
                        
						this.Activate();

						POINT mousePos;
						mousePos.x = (short)((int)m.LParam & 0x0000FFFFU);
						mousePos.y = (short)(int)(((int)m.LParam & 0xFFFF0000U) >> 16);

						Point topLeft = PointToScreen(new Point(0, 0));
						topLeft.Y -= SystemInformation.CaptionHeight;
						topLeft.X -= SystemInformation.BorderSize.Width;

						mredocker = new RedockerContent(this, new Point(mousePos.x - topLeft.X, 
							mousePos.y - topLeft.Y));
                        
                        
						return;
					}
				}
			}
			else if (m.Msg == (int)Msgs.WM_MOUSEMOVE)
			{
				if (mintercept)
				{
					POINT mousePos;
					mousePos.x = (short)((int)m.LParam & 0x0000FFFFU);
					mousePos.y = (short)(int)(((int)m.LParam & 0xFFFF0000U) >> 16);

					mredocker.OnMouseMove(new MouseEventArgs(MouseButtons.Left, 
						0, mousePos.x, mousePos.y, 0));
                
					return;
				}
			}
			else if ((m.Msg == (int)Msgs.WM_RBUTTONDOWN) ||
				(m.Msg == (int)Msgs.WM_MBUTTONDOWN))
			{
				if (mintercept)
				{
					POINT mousePos;
					mousePos.x = (short)((int)m.LParam & 0x0000FFFFU);
					mousePos.y = (short)(int)(((int)m.LParam & 0xFFFF0000U) >> 16);

					mredocker.QuitTrackingMode(new MouseEventArgs(MouseButtons.Left, 
						0, mousePos.x, mousePos.y, 0));
                
					this.Capture = false;
                    
					mintercept = false;

					return;
				}
			}
			else if (m.Msg == (int)Msgs.WM_LBUTTONUP)
			{
				if (mintercept)
				{
					POINT mousePos;
					mousePos.x = (short)((int)m.LParam & 0x0000FFFFU);
					mousePos.y = (short)(int)(((int)m.LParam & 0xFFFF0000U) >> 16);
		
					mredocker.OnMouseUp(new MouseEventArgs(MouseButtons.Left, 0, 
						mousePos.x, mousePos.y, 0));

					this.Capture = false;
                    
					mintercept = false;

					return;
				}
			} 
			else if ((m.Msg == (int)Msgs.WM_NCRBUTTONUP) ||
				(m.Msg == (int)Msgs.WM_NCMBUTTONDOWN) ||
				(m.Msg == (int)Msgs.WM_NCMBUTTONUP) ||
				(m.Msg == (int)Msgs.WM_RBUTTONDOWN) ||
				(m.Msg == (int)Msgs.WM_RBUTTONUP) ||
				(m.Msg == (int)Msgs.WM_MBUTTONDOWN) ||
				(m.Msg == (int)Msgs.WM_MBUTTONUP))
			{
				return;
			} 
			else if (m.Msg == (int)Msgs.WM_NCRBUTTONDOWN)
			{
				if (!mintercept)
				{
					POINT mousePos;
					mousePos.x = (short)((int)m.LParam & 0x0000FFFFU);
					mousePos.y = (short)(int)(((int)m.LParam & 0xFFFF0000U) >> 16);
        			
					OnContext(new Point(mousePos.x, mousePos.y));

					return;		
				}
			}

			base.WndProc(ref m);
		}

		#endregion

		#region Overrides

		[UseApiElements("WindowExStyles.WS_EX_TOOLWINDOW")]
		protected override CreateParams CreateParams 
		{
			[SecurityPermission(SecurityAction.LinkDemand)]
			get 
			{
				CreateParams cp = base.CreateParams;
				cp.ExStyle |= (int)WindowExStyles.WS_EX_TOOLWINDOW;

				return cp;
			}
		}

		protected override void OnMove(EventArgs e)
		{
			Point newPos = this.Location;
			
			ContentCollection cc = ZoneHelper.Contents(mzone);
			
			foreach(Content c in cc)
				c.DisplayLocation = newPos;			

			base.OnMove(e);
		}

		protected override void OnClosing(CancelEventArgs e)
		{
			if (mzone != null)
			{
				ContentCollection cc = ZoneHelper.Contents(mzone);

				foreach(Content c in cc)
					c.RecordRestore();

				foreach(Content c in cc)
                {
					if (!mdockingManager.OnContentHiding(c))
					{
						mdockingManager.HideContent(c, false, true);

						if (c.CloseOnHide)
						{
							mdockingManager.Contents.Remove(c);

							if (c.Control != null)
								c.Control.Dispose();
						}
					}
					else
					{
						e.Cancel = true;
					}
                }
			}

			if (this.Owner != null)
				this.Owner.Activate();

			base.OnClosing(e);
		}

        protected override void OnResize(System.EventArgs e)
        {
            ContentCollection cc = ZoneHelper.Contents(mzone);
			
			Size newSize = new Size(this.Width, this.Height - SystemInformation.ToolWindowCaptionHeight);
			
            foreach(Content c in cc)
                c.FloatingSize = newSize;

            base.OnResize(e);
        }

		#endregion

		#region Methods

		[UseApiElements("WM_KEYDOWN, VK_ESCAPE")]
		public bool PreFilterMessage(ref Message m)
		{
			if (m.Msg == (int)Msgs.WM_KEYDOWN)
			{
				if ((int)m.WParam == (int)VirtualKeys.VK_ESCAPE)
				{                   
					if (mintercept)
					{
						mredocker.QuitTrackingMode(null);

						this.Capture = false;
                    
						mintercept = false;

						return true;
					}
				}
			}
            
			return false;
		}

		public void ExitFloating()
		{
			if (mzone != null)
			{
				ContentCollection cc = ZoneHelper.Contents(mzone);

				foreach(Content c in cc)
				{
					c.RecordFloatingRestore();
					c.Docked = true;
				}
			}
		}

		public void PropogateNameValue(PropogateName name, object value)
		{
			if (this.Zone != null)
				this.Zone.PropogateNameValue(name, value);
		}
        
		public void AddHotZones(Redocker redock, HotZoneCollection collection)
		{
			RedockerContent redocker = redock as RedockerContent;

			foreach(Control c in this.Controls)
			{
				IHotZoneSource ag = c as IHotZoneSource;

				if (ag != null)
					ag.AddHotZones(redock, collection);
			}
		}

		#endregion

		#region Properties

		public DockingManager DockingManager
		{
			get { return mdockingManager; }
		}

		public Zone Zone
		{
			get { return this.Controls[0] as Zone; }
		}

		#endregion
	}
}
